package fr.emse.tatiana.graphical;

import java.util.HashSet;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
import java.util.Vector;

import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Ellipse;
import org.eclipse.draw2d.RectangleFigure;
import org.eclipse.draw2d.RoundedRectangle;
import org.eclipse.draw2d.Shape;
import org.eclipse.draw2d.Triangle;
import org.eclipse.swt.graphics.Color;
import org.nfunk.jep.*;


import fr.emse.tatiana.replayable.IReplayableModel;

public class DisplayRule {

	public static final String VISIBLE = "visible";
	public static final String COLOR = "colour";
	public static final String BORDER_COLOR = "border colour";
	public static final String POSITION = "relative position";
	public static final String HEIGHT = "height";
	public static final String SET_POSITION = "absolute position";
	public static final String SHAPE = "shape";
	public static final String[] properties = {VISIBLE, COLOR, BORDER_COLOR, POSITION, SET_POSITION,  HEIGHT, SHAPE};


	private String facetname;
	private String facetvalue;
	private String property;
	private String propertyvalue;

	public DisplayRule(String facet, String facetvalue, String property,
			String propertyvalue) {
		this.facetname = facet;
		this.facetvalue = facetvalue;
		this.property = property;
		this.propertyvalue = propertyvalue;
	}

	
	public boolean test(IReplayableModel model, Object event) {
		if (facetname==null && facetvalue==null) {
			return true;
		} else if (facetname==null) {
			for (int i=0; i< model.getFacetCount(); i++) {
				if (model.getFacetText(event, i).equals(facetvalue)) {
					return true;
				}
			}
		} else if (facetvalue==null) {
			return model.getFacetCol(facetname) > 0 ; // TODO fix for when facets are not always set
		} else {
			try {
				return (model.getFacetText(event, model.getFacetCol(facetname)).equals(facetvalue));
			} catch (Exception e) {
				// do nothing - facet is currently out of bounds
			}
		}
		return false;
	}

	public void apply(final IReplayableModel model, final Object event, IRuleableFigure f) {
		if (!test(model,event))
			return;

		try {
			final JEP parser = new JEP();
			parser.setAllowUndeclared(true);
			parser.getSymbolTable().addObserver(new Observer() {

				public void update(Observable arg0, Object arg1) {
					if(arg0 instanceof SymbolTable.StObservable)
					{
						Variable v = (Variable) arg1;
						if (v.getName().startsWith("$")) {
							Integer value;
							Color color;
							int dollarcount = 1;
							if (v.getName().startsWith("$$")) dollarcount = 2;
							String facetname = v.getName().substring(dollarcount);
							int f;
							for (f=0;f<model.getFacetCount(); f++) {
								if (facetname.equals(prepareFacet(model.getFacetName(f)))) {
									break;
								}
							}
							if (f<model.getFacetCount()) {
								if (dollarcount == 1) {
									try {
										value = Integer.parseInt(model.getFacetText(event, f));
									} catch (NumberFormatException nfe) {
										Set<String> set = new HashSet<String>();
										for (int row=0; row<model.getEventCount(); row++) {
											String s = model.getFacetText(row, f);
											set.add(s);
										}
										Vector<String> vec = new Vector<String>(set);
										value = vec.indexOf(model.getFacetText(event, f));
									}
									v.setValue(value.doubleValue());
								} else {
									try {
										color = model.getBackground(event, f);
									} catch (Exception e) {
										color = ColorConstants.white;
									}
									if (color !=null) v.setValue(new Double((double) color.getBlue()+color.getRed()*256*256+color.getGreen()*256));
								}
							}
						}
						
					}
				}

			});

			int blue = 0x0000ff;
			int red = 0xff0000;
			int green = 0x00ff00;
			int gray = 0x999999;
			int lightgray = 0xcccccc;
			int darkgray = 0x555555;
			parser.addVariable("blue", blue);
			parser.addVariable("red", red);
			parser.addVariable("green", green);
			parser.addVariable("gray", gray);
			parser.addVariable("lightgray", lightgray);
			parser.addVariable("darkgray", darkgray);
			parser.addVariable("none",0);
			parser.addVariable("circle",1);
			parser.addVariable("square", 2);
			parser.addVariable("rounded",3);
			parser.addVariable("triangle",4);
			parser.addVariable("octogon",5);
			Integer currentvalue = null;
			parser.parseExpression((propertyvalue==null) ? "$"+prepareFacet(facetname) : propertyvalue);
			currentvalue = (int) parser.getValue();

			boolean b = (currentvalue>0);
			int i =  currentvalue;
			Color c =  new Color(null, (currentvalue & red)>>16, (currentvalue & green)>>8, currentvalue & blue); // 
			if (VISIBLE.equals(property)) {
				f.setVisible(b);
			} else if (COLOR.equals(property)) {
				if (c!=null)
					f.setBackgroundColor(c);
			} else if (BORDER_COLOR.equals(property)) {
				if (c!=null)
					f.setBorderColor(c);
			} else if (HEIGHT.equals(property)) {
				f.setHeight(i);
			} else if (POSITION.equals(property)) {
				f.moveY(i);
			} else if (SET_POSITION.equals(property)) {
				f.setAbsoluteY(i);
			} else if (SHAPE.equals(property)) {
				Shape shape;
				switch (i) {
				case 1:
					shape = new Ellipse();
					break;
				case 2:
					shape = new RectangleFigure();
					break;
				case 3:
					shape = new RoundedRectangle();
					break;
				case 4:
					shape = new Triangle();
					break;
				case 5:
					shape = new Octagon();
					break;
				case 0:
				default:
					shape = null;
				}
				f.setShape(shape);
			}
			} catch (NullPointerException e) {
				e.printStackTrace();
			} catch (ClassCastException ce) {
				ce.printStackTrace();
			}

		}

		/**
		 * @return the facet
		 */
		public String getFacet() {
			return facetname;
		}

		/**
		 * @return the facetvalue
		 */
		public String getFacetvalue() {
			return facetvalue;
		}

		/**
		 * @return the property
		 */
		public String getProperty() {
			return property;
		}

		/**
		 * @return the propertyvalue
		 */
		public String getPropertyvalue() {
			return propertyvalue;
		}

		public void shiftFacet() {
// no longer necessary?

		}

		public static String prepareFacet(String facet) {
			String ret = facet.replace(' ', '_');
			ret = ret.replace('-', '_');
			return ret;
		}

	}
